package br.cin.ufpe.feedbacktest.core;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;

public class CallFilter {

	public static boolean isAllowed(Class<?> callClass){
		boolean allow = false;
		if(Modifier.isPublic(callClass.getModifiers())){
			if(callClass.isInterface()){
				if(callClass.equals(Comparable.class) ||
					callClass.equals(Collection.class)){
					allow = true;
				}
			}else{
				allow = true;
			}			
		}
		return allow;
	}

	public static boolean isAllowed(Constructor<?> constructor){
		boolean allow = false;

		int modifiers = constructor.getModifiers();
		if(Modifier.isPublic(modifiers) &&
				!Modifier.isAbstract(constructor.getDeclaringClass().getModifiers()) &&
				parametersAllowed(constructor)){
			allow = true;
		}

		return allow;
	}

	public static boolean isAllowed(Method method){
		int modifiers = method.getModifiers();
		boolean allow = false;

		if (!Modifier.isAbstract(modifiers) && 
				Modifier.isPublic(modifiers) && 
				!method.isBridge() &&
				!method.isSynthetic() &&
				!method.getDeclaringClass().equals(java.lang.Object.class) &&
				!method.getDeclaringClass().equals(java.lang.Thread.class) &&
				parametersAllowed(method)) {
			allow = true;
		}

		return allow;
	}

	private static boolean parametersAllowed(Method method){
		boolean allow = true;

		Class<?>[] parameterClasses = method.getParameterTypes();
		Constructor<?>[] constructors = null;
		Class<?> c = null;

		for(int index = 0; index < parameterClasses.length && allow; index++){
			c = parameterClasses[index];
			
			if(!isAllowed(c)){
				allow = false;
				break;
			}

			if(c.isPrimitive() ||
				c.getClass().equals(String.class)){
				continue;
			}
			
			constructors = c.getConstructors();

			for(Constructor<?> constructor:constructors){
				
				if(!parametersAllowed(constructor)){
					allow = false;
					break;
				}

			}			
			

		}

		return allow;
	}

	private static boolean parametersAllowed(Constructor<?> constructor){
		boolean allow = true;
		
		Class<?>[] parameters = constructor.getParameterTypes();
		
		for(Class<?> c: parameters){
			
			if(!isAllowed(c)){
				allow = false;
				break;
			}
			
			if(!c.isPrimitive() &&
				c.getClass().equals(String.class)){
				allow = false;
				break;
			}
			
		}

		return allow;
	}
}